import subprocess
import threading
import time
import os
from flask import Blueprint, jsonify, request, current_app
from app.models.system import SystemLog
from app import socketio

updates_bp = Blueprint('updates', __name__)

# 保存更新状态
update_status = {
    'checking': False,
    'last_check': None,
    'available_updates': [],
    'updating': False,
    'update_progress': 0,
    'update_message': '',
    'last_update': None
}

def run_command(cmd, timeout=60):
    """运行命令并返回结果"""
    try:
        process = subprocess.Popen(
            cmd, 
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            shell=True,
            text=True
        )
        stdout, stderr = process.communicate(timeout=timeout)
        return {
            'success': process.returncode == 0,
            'code': process.returncode,
            'stdout': stdout,
            'stderr': stderr
        }
    except subprocess.TimeoutExpired:
        process.kill()
        return {
            'success': False,
            'code': -1,
            'stdout': '',
            'stderr': 'Command timed out'
        }
    except Exception as e:
        return {
            'success': False,
            'code': -1,
            'stdout': '',
            'stderr': str(e)
        }

def parse_apt_updates(output):
    """解析apt更新列表输出"""
    updates = []
    lines = output.split('\n')
    for line in lines:
        if line.startswith('Inst'):
            parts = line.split()
            if len(parts) >= 4:
                package = parts[1]
                # 格式: Inst package [current_version] (new_version)
                current_version = parts[2].strip('[]') if '[' in parts[2] else ''
                new_version = ''
                
                # 提取新版本
                for i, part in enumerate(parts):
                    if part.startswith('(') and i < len(parts)-1:
                        new_version = part.strip('(') + ' ' + parts[i+1].strip(')')
                        break
                
                updates.append({
                    'package': package,
                    'current_version': current_version,
                    'new_version': new_version,
                    'security': 'security' in line.lower()
                })
    return updates

def check_updates_thread():
    """检查更新的线程函数"""
    global update_status
    
    try:
        update_status['checking'] = True
        update_status['available_updates'] = []
        
        # 更新软件包列表
        SystemLog.log("INFO", "updates", "开始检查更新")
        result = run_command('apt-get update', timeout=120)
        
        if not result['success']:
            SystemLog.log("ERROR", "updates", f"更新软件包列表失败: {result['stderr']}")
            update_status['checking'] = False
            update_status['last_check'] = time.time()
            socketio.emit('update_status', update_status)
            return
        
        # 获取可更新的包列表
        result = run_command('apt-get --simulate dist-upgrade', timeout=60)
        
        if result['success']:
            updates = parse_apt_updates(result['stdout'])
            update_status['available_updates'] = updates
            SystemLog.log("INFO", "updates", f"发现{len(updates)}个可用更新")
        else:
            SystemLog.log("ERROR", "updates", f"检查更新失败: {result['stderr']}")
        
    except Exception as e:
        SystemLog.log("ERROR", "updates", f"检查更新异常: {str(e)}")
    finally:
        update_status['checking'] = False
        update_status['last_check'] = time.time()
        socketio.emit('update_status', update_status)

def install_updates_thread():
    """安装更新的线程函数"""
    global update_status
    
    try:
        update_status['updating'] = True
        update_status['update_progress'] = 0
        update_status['update_message'] = '准备更新...'
        socketio.emit('update_status', update_status)
        
        SystemLog.log("INFO", "updates", "开始安装系统更新")
        
        # 更新软件包列表
        update_status['update_progress'] = 10
        update_status['update_message'] = '更新软件包列表...'
        socketio.emit('update_status', update_status)
        
        result = run_command('apt-get update', timeout=120)
        if not result['success']:
            update_status['update_message'] = f"更新软件包列表失败: {result['stderr']}"
            SystemLog.log("ERROR", "updates", update_status['update_message'])
            socketio.emit('update_status', update_status)
            update_status['updating'] = False
            return
        
        # 安装更新
        update_status['update_progress'] = 30
        update_status['update_message'] = '安装更新...'
        socketio.emit('update_status', update_status)
        
        # 使用非交互模式安装更新
        os.environ['DEBIAN_FRONTEND'] = 'noninteractive'
        result = run_command('apt-get -y dist-upgrade', timeout=600)  # 允许10分钟
        
        if not result['success']:
            update_status['update_message'] = f"安装更新失败: {result['stderr']}"
            SystemLog.log("ERROR", "updates", update_status['update_message'])
            socketio.emit('update_status', update_status)
            update_status['updating'] = False
            return
        
        # 清理
        update_status['update_progress'] = 80
        update_status['update_message'] = '清理...'
        socketio.emit('update_status', update_status)
        
        result = run_command('apt-get -y autoremove', timeout=120)
        if not result['success']:
            SystemLog.log("WARNING", "updates", f"自动清理失败: {result['stderr']}")
        
        # 完成
        update_status['update_progress'] = 100
        update_status['update_message'] = '更新完成'
        update_status['available_updates'] = []
        update_status['last_update'] = time.time()
        SystemLog.log("INFO", "updates", "系统更新完成")
        
    except Exception as e:
        update_status['update_message'] = f"更新过程异常: {str(e)}"
        SystemLog.log("ERROR", "updates", update_status['update_message'])
    finally:
        update_status['updating'] = False
        socketio.emit('update_status', update_status)

@updates_bp.route('/check', methods=['GET'])
def check_updates():
    """检查系统更新"""
    global update_status
    
    if update_status['checking']:
        return jsonify({
            'status': 'checking',
            'message': '正在检查更新...'
        })
    
    # 启动检查线程
    thread = threading.Thread(target=check_updates_thread)
    thread.daemon = True
    thread.start()
    
    return jsonify({
        'status': 'started',
        'message': '开始检查更新'
    })

@updates_bp.route('/status', methods=['GET'])
def get_update_status():
    """获取更新状态"""
    global update_status
    
    return jsonify(update_status)

@updates_bp.route('/install', methods=['POST'])
def install_updates():
    """安装系统更新"""
    global update_status
    
    if update_status['updating']:
        return jsonify({
            'status': 'updating',
            'message': '更新已在进行中'
        }), 409
    
    if not update_status['available_updates']:
        return jsonify({
            'status': 'no_updates',
            'message': '没有可用更新'
        })
    
    # 启动更新线程
    thread = threading.Thread(target=install_updates_thread)
    thread.daemon = True
    thread.start()
    
    return jsonify({
        'status': 'started',
        'message': '开始安装更新'
    }) 